package de.dvdverleih.dao;

import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;

import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import de.dvdverleih.dto.VerleihDTO;
import de.dvdverleih.model.Dvd;
import de.dvdverleih.model.Kunden;
import de.dvdverleih.model.Verleih;
import de.dvdverleih.dao.VerleihDao;

/**
 * @author Landsberger, Neitzsch, Baier
 */

public class VerleihDao extends HibernateDaoSupport {
	SimpleDateFormat deutschesDatumsFormat = new SimpleDateFormat("dd.MM.yyyy");

	/**
	 * 
	 * Method for returning all {@link Verleih} objects in the database.
	 * @return 
	 * 			a list of all objects
	 * 
	 */
	@SuppressWarnings("unchecked")
	public List<Verleih> findAll() {
		HibernateTemplate template = getHibernateTemplate();
		@SuppressWarnings("rawtypes")
		List alleVerleih = template.loadAll(Verleih.class);
		return (List<Verleih>) alleVerleih;
	}

	/**
	 * 
	 * <p>Method for saving {@link Verleih} specified by the parameter in the database.</p>
	 * <p>The method works as follows:</p>
	 * <ul>
	 * <li>Geting a {@link Kunden} by his primary key (kdId) from the database.</li>
	 * <li>Getting a {@link Dvd} by his primary key (dvdId) from the database.</li>
	 * <li>Creating new {@link Verleih} with the customer and dvd found in database.</li>
	 * <li>Saveing or updating data.</li>
	 * </ul>
	 * @param kdId
	 *            {@link Kunden} primary key
	 * @param dvdId
	 *            {@link Dvd} primary key
	 * 
	 */
	public void saveVerleih(int kdId, int dvdId) {
		HibernateTemplate template = getHibernateTemplate();
		Kunden k = (Kunden) template.get(Kunden.class, kdId);
		Dvd d = (Dvd) template.get(Dvd.class, dvdId);
		Verleih v = new Verleih();
		v.setKunden(k);
		v.setDvd(d);
		template.saveOrUpdate(v);
	}

	/**
	 * 
	 * Method for returning a single hiring by his primary key in the database.
	 * @param id
	 *            primary key of {@link Verleih}
	 * @return a single hiring
	 * 
	 */
	public Verleih findById(int id) {
		HibernateTemplate template = getHibernateTemplate();
		return (Verleih) template.get(Verleih.class, id);
	}

	/**
	 * 
	 * Method for deleting a {@link Verleih} from the database.
	 * @param verleih
	 *            {@link Verleih} that should be deleted.
	 * 
	 */
	public void delete(Verleih verleih) {
		HibernateTemplate template = getHibernateTemplate();
		template.delete(verleih);
	}

	/**
	 * 
	 * <p>Starts a hiring specified by a user ID (kundenId) and a dvd ID (dvdID).</p>
	 * <p>The method works as follows:</p>
	 * <ul>
	 * <li>Geting a {@link Kunden} by his primary key (kdId) from the database.</li>
	 * <li>Getting a {@link Dvd} by his primary key (dvdId) from the database.</li>
	 * <li>Creating new {@link Verleih} with the customer and dvd found in the database.</li>
	 * <li>Saveing or updating data.</li>
	 * </ul>
	 * @param kundenId
	 *            primary key of a customer
	 * @param dvdId
	 *            primary key of a dvd
	 * 
	 */
	public void beginne(int kundenId, int dvdId) {
		HibernateTemplate template = getHibernateTemplate();
		Kunden kunden = (Kunden) template.get(Kunden.class, kundenId);
		Dvd dvd = (Dvd) template.get(Dvd.class, dvdId);
		Verleih v = new Verleih();
		v.setKunden(kunden);
		v.setDvd(dvd);
		template.saveOrUpdate(v);
	}

	/**
	 * 
	 * Method for ending a hiring by adding a return date (Rueckgabedatum).
	 * @param id
	 *            primary key of the hiring
	 * 
	 */
	public void beende(Integer id) {
		HibernateTemplate template = getHibernateTemplate();
		Verleih v = (Verleih) template.get(Verleih.class, id);
		v.setRueckgabedatum(new Date());
		template.saveOrUpdate(v);
	}

	/**
	 * 
	 * <p>Method for returning all hiring objects as "VerleihDTO" objects.</p>
	 * <p>In order to ..., a HibernateCallback is used.</p>
	 * @return 
	 * 			a DTO-Set of all hirings
	 * 
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Set<VerleihDTO> findAllDTO() {
		HibernateTemplate template = getHibernateTemplate();
		return (Set<VerleihDTO>) template.execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Criteria criteria = session.createCriteria(Verleih.class);
				criteria.add(Restrictions.isNotNull("ausleihdatum"));
				List<Verleih> alleVerleih = criteria.list();
				return createDtoSet(alleVerleih);
			}
		});
	}

	/**
	 * 
	 * <p>Method for creating a new DTO-Set.</p>
	 * <p>The returned result includes:</p>
	 * <ul>
	 * <li>Titel of the dvd</li>
	 * <li>Name of the customer</li>
	 * <li>Date of hiring</li>
	 * <li>Return date of hiring</li>
	 * </ul>
	 * @param verleih
	 * @return
	 * 			results with a parameter list of the customer
	 * 
	 */
	private Set<VerleihDTO> createDtoSet(List<Verleih> verleih) {
		Set<VerleihDTO> results = new TreeSet<VerleihDTO>();
		for (Verleih v : verleih) {
			v.getRueckgabedatum();
			results.add(new VerleihDTO(v.getId(), v.getDvd().getTitel(), v
					.getKunden().getVorname(), v.getKunden().getNachname(), v
					.getAusleihdatum(), v.getRueckgabedatum()));
		}
		return results;
	}

	/**
	 * 
	 * Method for finding not ended DTOs.
	 * @param verleih
	 * @return
	 * 			results with a parameter list of the customer
	 * 
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Set<VerleihDTO> findNichtBeendetDTO() {
		HibernateTemplate template = getHibernateTemplate();
		return (Set<VerleihDTO>) template.execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Criteria criteria = session.createCriteria(Verleih.class);
				criteria.add(Restrictions.isNull("rueckgabedatum"));
				List<Verleih> alleVerleih = criteria.list();
				return createDtoSet(alleVerleih);
			}
		});
	}

}
